#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>

#include "global.h"
#include "constantes.h"
#include "sockets.h"
#include "NIPC.h"
#include "listas.h"
#include "sincronizador.h"


extern int numeroSincro;
extern int contador;

	
void *syncer(void *args) {
    
	disco * dsk = (struct DiscoConocido *) args;	
	
	numeroSincro++;
	int owner = numeroSincro;
	int i,j,ret,flag,salto;
	
	char* vacia=(char *)malloc(512);
	memset(vacia,'\0',512);
	
	while(dsk->sectores < 1048576)
	{
		
		disco* discoElegido = (disco*)asignarread((dsk->sectores), owner);
		
		salto=0;
		
		flag=0;
		
		while(!flag){
		

				ret=pthread_mutex_trylock(&mutex);
				
				if (ret==0)
				{
					
					struct ListaIDdescriptors *nodo = BuscarPedidoEnListaDeDisco_Lect(colaGlobal, colaGlobal_Ult,dsk->sectores, owner);
					if(nodo != NULL){
						SacarNodoDescriptoresDeLista2(&nodo, &(colaGlobal),&(colaGlobal_Ult));
						
						if(!(strcmp(nodo->data,vacia))){
							dsk->sectores++;
							salto=1;
						}
						else
							asignarwrite(dsk,owner,nodo->numeroSector,nodo->data);
						
						free(nodo);
						discoElegido->pendings--;
						flag=1;
					}
					
					if(pthread_mutex_unlock(&mutex)!=0){
						perror("pthread_mutex_lock");
						exit(EXIT_FAILURE);
					}

					
				}
				
		}
			
			
		flag=0;
		
		if(salto)
			salto=0;
		else{
			while(!flag){	
				
				ret=pthread_mutex_trylock(&mutex);
				
				if (ret==0)
				{
					struct ListaIDdescriptors *nodo=BuscarPedidoEnListaDeDisco_Escr(colaGlobal,colaGlobal_Ult, owner);
					if(nodo != NULL){
						SacarNodoDescriptoresDeLista2(&nodo, &colaGlobal,&(colaGlobal_Ult));
						free(nodo);
						dsk->pendings--;
						dsk->sectores++;
						flag=1;
					}
					if(pthread_mutex_unlock(&mutex)!=0){
						perror("pthread_mutex_lock");
						exit(EXIT_FAILURE);
					}
					
					
				}
			}
		}
		
		if(dsk->sectores==100000 || dsk->sectores==200000 || dsk->sectores==300000  || dsk->sectores==400000  || dsk->sectores==500000  || dsk->sectores==600000  || dsk->sectores==700000  || dsk->sectores==800000  || dsk->sectores==900000  || dsk->sectores==1000000 )
			printf("Se sincronizaron los primeros %i sectores\n",dsk->sectores);
	
	}
	
	printf("Se finalizo la sincronizacion del disco %s\n", dsk->sNombre);
	dsk->Estado = LISTO;
	printf("DISCO LISTO\n");

}


disco* asignarread(int sector, int owner) {
    
	char * sContador=(char*)malloc(20);
	int payload;
	char *sAux=(char *)malloc(20);
	int ret;
	int tamanio_buff ;
	char *buffer;
	
	disco *dsk = (disco *)elegirDisco(sector);
	
	
	if(pthread_mutex_lock(&(mutex3))!=0){
		perror("pthread_mutex_lock");
		exit(EXIT_FAILURE);
	}
			
	contador++;			
			
	if(pthread_mutex_unlock(&(mutex3))!=0){
		perror("pthread_mutex_lock");
		exit(EXIT_FAILURE);
	}
	
	
	intacad(contador,sContador);
	
	pedido * NodoDescriptores = (struct ListaIDdescriptors *)malloc(sizeof(struct ListaIDdescriptors));
	strcpy(NodoDescriptores->sSocketPorElCualResponder,"-1");
	strcpy(NodoDescriptores->discoAsignado,dsk->sNombre);
	strcpy(NodoDescriptores->sDescriptorID_delPedido,sContador);
	NodoDescriptores->numeroSector=sector;
	NodoDescriptores->estado=0;
	NodoDescriptores->operacion=0;
	NodoDescriptores->owner=owner;
	NodoDescriptores->Sgt = NULL;
	NodoDescriptores->Ant = NULL;


	
	AgregarAColaDePedidosADisco(&NodoDescriptores,&(colaGlobal),&(colaGlobal_Ult));

	
	memset(sAux,'\0',20);
	intacad(NodoDescriptores->numeroSector,sAux);	
	
	payload=READ_SECTORSYNC_REQUEST;
	
	tamanio_buff = strlen(NodoDescriptores->sDescriptorID_delPedido) + 1 + strlen(sAux) + 2 ;
	buffer = (char *) malloc (sizeof(char) * tamanio_buff);

	strcpy(buffer, NodoDescriptores->sDescriptorID_delPedido);
	strcat(buffer, ",");
	strcat(buffer, sAux);
	strcat(buffer, ";");
		
	
	InfoIPC rInfoIPC3;
	rInfoIPC3.payLoadLength=tamanio_buff;
	generarStructIPC(buffer,payload,&rInfoIPC3);
	enviarIPC(dsk->iSocketHDAParaDA,&rInfoIPC3);	
	free(rInfoIPC3.payload);
	NodoDescriptores->estado = 1;
	
	free(buffer);
	free(sAux);
	free(sContador);
	
	return dsk;
}

void asignarwrite(struct DiscoConocido *dsk, int owner,int sector,char *data) {
	
	char * sContador=(char*)malloc(20);
	int payload;
	char *sAux=(char *)malloc(20);
	int ret; 
	int tamanio_buff ;
	char *buffer; 
	 
	

	if(pthread_mutex_lock(&(mutex3))!=0){
		perror("pthread_mutex_lock");
		exit(EXIT_FAILURE);
	}
	
	contador++;			
		
	if(pthread_mutex_unlock(&(mutex3))!=0){
		perror("pthread_mutex_lock");
		exit(EXIT_FAILURE);
	}
	
	
	intacad(contador,sContador);
	
	pedido * NodoDescriptores = (struct ListaIDdescriptors *)malloc(sizeof(struct ListaIDdescriptors));
	strcpy(NodoDescriptores->sSocketPorElCualResponder,"-1");
	strcpy(NodoDescriptores->discoAsignado,dsk->sNombre);
	strcpy(NodoDescriptores->sDescriptorID_delPedido,sContador);
	NodoDescriptores->numeroSector=sector;
	memcpy(NodoDescriptores->data,data,512);
	NodoDescriptores->estado=0;
	NodoDescriptores->operacion=1;
	NodoDescriptores->owner=owner;
	NodoDescriptores->Sgt = NULL;
	NodoDescriptores->Ant = NULL;
	
			
	AgregarAColaDePedidosADisco(&NodoDescriptores,&(colaGlobal),&(colaGlobal_Ult));

	
	dsk->pendings++;
	
	memset(sAux,'\0',20);
	intacad(NodoDescriptores->numeroSector,sAux);	
	payload=WRITE_SECTORSYNC_REQUEST;
	tamanio_buff = strlen(NodoDescriptores->sDescriptorID_delPedido) + 1 + strlen(sAux) + 1 + 512 + 1;
	buffer = (char *) malloc (sizeof(char) * tamanio_buff);
	strcpy(buffer, NodoDescriptores->sDescriptorID_delPedido);
	strcat(buffer, ",");
	strcat(buffer, sAux);
	strcat(buffer, ";");
	memcpy(buffer + strlen(NodoDescriptores->sDescriptorID_delPedido) + 1 + strlen(sAux) + 1, NodoDescriptores->data, 512);
	InfoIPC rInfoIPC3;
	rInfoIPC3.payLoadLength=tamanio_buff;
	generarStructIPC(buffer,payload,&rInfoIPC3);
	enviarIPC(dsk->iSocketHDAParaDA,&rInfoIPC3);	
		free(rInfoIPC3.payload);
	NodoDescriptores->estado = 1;
	
	free(buffer);
	free(sAux);
	free(sContador);
	
}
